if (!_log) {
	_log = alert;
}


function TimeoutCache(timeout_s, size) {
	this.size = size;
	this.timeout = timeout_s;
		
	this.clear = function() {
		this.size = this.size;
		this.front = 0;
		this.back = 0;
		this.keys = new Array(this.size);
		this.cache = new Array(this.size);
		this.timestamps = new Array(this.size);
		
		_log("(timeoutcache) new: (size: " + this.size + ")");
	};
	
	this.put = function(key, value, stamp) {
		_log("(timeoutcache) put: (" + key + ", " + value + ", " + stamp + ")");
		
		stamp = stamp || this._timestamp();
	
		if (!this.update(key, value, stamp)) {
			return this.insert(key, value, stamp);
		}
		
		return null;
	};
	
	this.insert = function(key, value, stamp) {
		_log("(timeoutcache) insert: (" + key + ", " + value + ", " + stamp + ")");
	
		this.keys[key] = this.front;
		this.cache[this.front] = value;
		this.timestamps[this.front] = stamp || this._timestamp();
		
		_log("(timeoutcache) insert at: (" + this.front + ", " + value + ", " + this.timestamps[this.front] + ")");
		
		this.front = this.front + 1;
		
		if (this.size) {
			this.front %= this.size;
		}
		
		return true;
	}
	
	this.get = function(key) {
		_log("(timeoutcache) get: (" + key + ")");
		return this.cache[this.keys[key]] || null;
	};
	
	this.isCached = function(key) {
		var bool = this._containsKey(key) && !this._hasTimedOut(key);
		
		_log("(timeoutcache) isCached: (" + key + ") ? " + bool);
		
		return bool;
	};
	
	this._containsKey = function(key) {
		return !!this.cache[this.keys[key]];
	};
	
	this._hasTimedOut = function(key) {
		var then = this.timestamps[this.keys[key]];
		
		_log("(timeoutcache) then: " + then);
		
		if (then > 0) {
			var now = this._timestamp();
			var diff = now - then;
			var timeout = diff > this.timeout;
			
			
			_log("(timeoutcache) hasTimedOut: (" + key + ") ? diff: " + diff + " -> " + timeout);
			return timeout;
		}
			_log("(timeoutcache) hasTimedOut: (" + key + ") ? " + true);
		
		return true;
	};
	
	this._timestamp = function() {
		return new Date().setMilliseconds(0) / 1000;
	};
	
	this.update = function(key, value, stamp) {
		_log("(timeoutcache) update: (" + key + ", " + value + ", " + stamp + ")");
		
		if (!this.isCached(key)) {
			return false;
		}
		
		this.cache[this.keys[key]] = value;
		this.timestamps[this.keys[key]] = stamp || this._timestamp();
		
		return true;
	};
	
	this.isFull = function() {
		var full = this.timestamps[this.front] && this._hasTimedOut(this.keys[this.front]);
	
		if (this.size) {
			full = full && (this.front == this.size);
		}
		
		
		_log("(timeoutcache) isFull: (" + key + ") ? " + full);
		
		return full;
	};
	
	this.clear();
}